<?php

/**
 * @version		$Id: contpage.php 5 2012-01-24 03:49:13Z yuleivsc@gmail.com $
 * @package		Joomla
 */
// no direct access
defined('_JEXEC') or die;

jimport('joomla.plugin.plugin');

// 创建目录
function plgContpageCreateTOC(&$row, &$pageMatches, $P) {

    $toctext = '';
    $heading = $row->title;

    // TOC Header
    //$toctext = '<h1>'.$heading.'</h1>';
    $toctext = '';
    //$toctext .= '<h2>'.JText::_( 'Contents' ).'</h2>';

    $ipage = 2;

    $n = count($pageMatches);
    $clevel = 0;  // 当前标题层次
    $clsBase = 6; // 最外的层次
    // 此循环为了取得所有标题层次最外的层次
    for ($page = 0; $page < $n; $page++) {
        $matches = $pageMatches[$page];
        foreach ($matches as $bot) {
            if ($bot[1] < $clsBase && $bot[1]) {
                $clsBase = $bot[1];
            }
        }
    }
    $clevel = $clsBase;

    $tocnum = 0;
    for ($page = 0; $page < $n; $page++) {
        $matches = $pageMatches[$page];
        $ipage = $P['firstpagecontents'] ? $page + 2 : $page + 1;
        foreach ($matches as $bot) {
            //$bot[0] 整个<hn..>...</hn>
            //$bot[1] 标题层次
            //$bot[2] <hn xxxx>中的xxxx 标题的参数，如果有alt="xxxx",则xxxx为目录中显示的标题
            //$bot[3] <hn ...>xxxx</hn>中的xxxx部分，即正文中显示的标题
            $link = JRoute::_('&showall=&limitstart=' . ($ipage - 1));
            $link .= '#hntoc_' . $tocnum++;

            if (@$bot[0]) {
                $attrs2 = JUtility::parseAttributes($bot[0]);

                if (@$attrs2['alt']) {
                    $title = stripslashes($attrs2['alt']);
                } else {
                    $title = $bot[3];
                }
            } else {
                $title = JText::sprintf('无标题项目录 #', $ipage);
            }
            // $title = preg_replace( '/<.*>/', '', $title );
            $titletext = ' <a href="' . $link . '" class="toclink">' . $title . '</a> ';
            if ($bot[1] > $clevel) {
                $toctext .= str_repeat('<ul>', $bot[1] - $clevel);
            } elseif ($bot[1] < $clevel) {
                $toctext .= str_repeat('</ul>', $clevel - $bot[1]);
            }
            $clevel = $bot[1];
            $toctext .= '<li>' . $titletext . '</li>' . "\n";
        }
    }
    if ($clevel > $clsBase) {
        $toctext .= str_repeat('</ul>', $clevel - $clsBase);
    }

    // Get Plugin info
    $plugin = & JPluginHelper::getPlugin('content', 'newpage');
    return '<ul>' . $toctext . '</ul>';
}

/**
 * 创立页面浏览条（ << 1 2 ... >> ）
 */
function plgContpageCreateNavigation($page, $n, &$P) {

    $pagetext = '';
    if ($P['firstpagecontents'])
        $n++;
    $pagenav = array();
    $next = '';
    if ($page < $n - 1) {
        $page_next = $page + 1;

        $link_next = JRoute::_('&limitstart=' . ( $page_next ));
        // Next >>
        $next = '<a href="' . $link_next . '" alt="' . JText::_('Next') . '">' . JText::_('Next') . '</a>';
    }

    if ($page > 0) {
        $page_prev = $page - 1 == 0 ? "" : $page - 1;

        $link_prev = JRoute::_('&limitstart=' . ( $page_prev));
        // << Prev
        $prev = '<a href="' . $link_prev . '" alt="' . JText::_('Prev') . '">' . JText::_('Prev') . '</a>';
        $pagenav[] = $prev;
    }


    for ($i = 1; $i <= $n; $i++) {
        $link_page = JRoute::_('&limitstart=' . ( $i - 1));
        $label = $i;
        if ($i == 1) {
            $label = JText::_('First');
        }
        if ($page == $i - 1) {
            $pagetext = $label . ' ';
        } else {
            $pagetext = '<a href="' . $link_page . '">' . $label . '</a> ';
        }
        $pagenav[] = $pagetext;
    }
    if ($next)
        $pagenav[] = $next;

    $pagetext = implode(" | ", $pagenav);
    return '<div>' . $pagetext . '</div>';
}

/* 本插件涉及到的标签列举如下：
 *  任何带有 plugin="contpage" 的内容，表示本插件可用
 *  <hr class="system-option" aaa=bbb .... />  
 *      这里面的aaa=bbb代表选项设置，这些设置针对本文章，可以替换插件系统界面中的设置
 *      makefcontents  是否生成目录
 *      firstpagecontents 是否单独目录页
 *      contentslevel 目录显示到第几层标题
 *      pagrbreaklevel 第几层标题前分页
 *      hrpagebreak 使用传统的标签（hr class=system-pagebreak ）进行分页
 *      hrtagtoc 在标签hr class=system-toc处生成目录
 * <hr class=system-pagebreak>在此处分页
 * <hr class=system-toc> 在些处生成目录
 * <h1 alt="xxxxxxx" nopagebreak="1" >yyyyyyy</h1>
 *      h1代表第一级目录，这时，xxxxxxxx为目录中显示的目录标题，yyyyyyyy为正文中显示的正文标题
 *      如果没有设置alt="xxxxxxxx"，目录所中所显示的标题与正文中显示的标题相同
 *      如果设置了nopagebreak，则不管前面的的pagrbreaklevel如何设置，这个标题前不分页。
 *      如果没有nopagebreak，则按照pagrbreaklevel的设置进行分页
 *      (注意，只要出现了nopagebreak就不分页了)
 * <footnote text="xxxxxx"> 这里生成一条脚注。脚注内容是xxxxxxx
 */

/**
 * Contpage plugin.
 *
 * @package	Joomla.Plugin
 * @subpackage	Content.contpage
 */
class plgContentContpage extends JPlugin {

    /**
     * 构造函数
     */
    public function __construct(& $subject, $config) {
        parent::__construct($subject, $config);
        $this->loadLanguage();
    }

    function plgContentContpage(&$subject, $params) {
        parent::__construct($subject, $params);
    }

    /**
     *
     * @param 	object		The article object.  Note $article->text is also available
     * @param 	object		The article params
     * @param 	int			The 'page' number
     */
    function onPrepareContent(&$row, &$params, $page=0) {

        // expression to search for
        $regex = '#<h([1-6])([^>]*?)>(.*?)<\/h[1-6]>#i';

        // Get Plugin info
        $plugin = & JPluginHelper::getPlugin('content', 'contpage');
        $pluginParams = new JParameter($plugin->params);

        $print = JRequest::getBool('print');

        if (!$pluginParams->get('enabled', 1)) {
            $print = true;
        }

        if ($print) {
            return true;
        }

        if (strpos($row->text, 'plugin="contpage') === false && strpos($row->text, 'plugin=\'contpage') === false) {
            return true;
        }

        $view = JRequest::getCmd('view');

        if ($params) {
            if (!JPluginHelper::isEnabled('content', 'contpage') || $params->get('intro_only') || $params->get('popup') || $view != 'article') {
                return true;
            }
        }

        if (!$page) {
            $page = 0;
        }

        $P['makefcontents'] = $pluginParams->get('makefcontents', 0); // 是否生成目录
        $P['firstpagecontents'] = $pluginParams->get('firstpagecontents', 0); // 单独目录页
        $P['contentslevel'] = $pluginParams->get('contentslevel', 3); // 目录显示到第几层标题
        $P['pagrbreaklevel'] = $pluginParams->get('pagrbreaklevel', 0); // 第几层标题前分页
        $P['hrpagebreak'] = $pluginParams->get('hrpagebreak', 1); // 使用传统的标签（hr class=system-pagebreak ）进行分页
        $P['hrtagtoc'] = $pluginParams->get('hrtagtoc', 1); // 在标签hr class=system-toc处生成目录
        // 本文文中单独配置的选项
        $OpPageRegex = '#<hr([^>]*?)class=(\"|\')system-option(\"|\')([^>]*?)\/*>#i';
        $matches = array();
        if (preg_match($OpPageRegex, $row->text, $matches)) {
            $option = JUtility::parseAttributes($matches[0]);
            if (array_key_exists('makefcontents', $option)) {
                $P['makefcontents'] = stripslashes($option['makefcontents']);
            }
            if (array_key_exists('firstpagecontents', $option)) {
                $P['firstpagecontents'] = stripslashes($option['firstpagecontents']);
            }
            if (array_key_exists('contentslevel', $option)) {
                $P['contentslevel'] = stripslashes($option['contentslevel']);
            }
            if (array_key_exists('pagrbreaklevel', $option)) {
                $P['pagrbreaklevel'] = stripslashes($option['pagrbreaklevel']);
            }
            if (array_key_exists('hrpagebreak', $option)) {
                $P['hrpagebreak'] = stripslashes($option['hrpagebreak']);
            }
            if (array_key_exists('hrtagtoc', $option)) {
                $P['hrtagtoc'] = stripslashes($option['hrtagtoc']);
            }
            $row->text = preg_replace($OpPageRegex, '', $row->text, 1);
        }

        if ($P['makefcontents'] == 0)
            $P['firstpagecontents'] = 0; // 如果不制作首目录，那么单独目录页就没有意义
        if (strpos($row->text, 'system-toc') && $P['hrtagtoc']) {
            $P['system-toc'] = true;                    // 文章中包含有system-toc标签
        }
        $P['thisurl'] = $_SERVER['REQUEST_URI'];
        $pos = strrpos($P['thisurl'], '#');
        if ($pos) {
            $P['thisurl'] = substr($_SERVER['REQUEST_URI'], 0, $pos - 1);
        }

        // 进行HN分页
        $pageTexts1 = array();
        if ($P['pagrbreaklevel']) {
            $pagrbreaklevel = 6;
            // 标记分页的正则表达式
            // 第一个括号返回目录级别，第二个返回h标签参数，每三个返回<hn>和</hn>之间的内容
            if ($P['pagrbreaklevel'] >= 1 && $P['pagrbreaklevel'] <= 6) {
                $pagrbreaklevel = trim($P['pagrbreaklevel']);
            }
            if ($pagrbreaklevel == 1) {
                $PageBreakRegex = '#<h(1)([^>]*?)>(.*?)<\/h1>#i';
            } else {
                $PageBreakRegex = '#<h([1-' . $pagrbreaklevel . '])([^>]*?)>(.*?)<\/h[1-' . $pagrbreaklevel . ']>#i';
            }
            // 进行分页
            $pageMatches = array();
            preg_match_all($PageBreakRegex, $row->text, $pageMatches, PREG_SET_ORDER);
            $texts = preg_split($PageBreakRegex, $row->text);
            $pagenum = count($texts);
            if ($pagenum > 1) {
                $pageTexts1[0] = $texts[0] . $pageMatches[0][0] . $texts[1];
                $pagenum--;
            } else {
                $pageTexts1[0] = $texts[0];
            }
            if ($pagenum > 1) {
                for ($i = 1; $i < $pagenum; $i++) {
                    $pageTexts1[$i] = $pageMatches[$i][0] . $texts[$i + 1];
                }
            }

            // hn中的nopagebreak处理
            $pagenum = count($pageTexts1);
            $pageTexts2 = array();
            $j = 0;
            for ($i = 0; $i < $pagenum; $i++) {
                if (strpos($pageMatches[$i][0], 'nopagebreak') === false) {
                    $pageTexts2[$j] = $pageTexts1[$i];
                } else {
                    if ($j > 0) {
                        $j--;
                        $pageTexts2[$j] .= $pageTexts1[$i];
                    }
                }
                $j++;
            }
            //　经过以上分页处理，得到：
            //   $pagenum 页数
            //   $pageTexts2包含着所有页的数组
        } else {
            $pageTexts2[0] = $row->text;
        }



        //进行HR分页
        if ($P['hrpagebreak']) {
            $pagenum = count($pageTexts2);
            $HrPageRegex = '#<hr([^>]*?)class=(\"|\')system-pagebreak(\"|\')([^>]*?)\/*>#i';
            $pageTexts = array();
            for ($i = 0; $i < $pagenum; $i++) {
                $pagetext = $pageTexts2[$i];
                $texts = preg_split($HrPageRegex, $pagetext);
                $pageTexts = array_merge($pageTexts, $texts);
            }
        } else {
            $pageTexts = $pageTexts2;
        }
        //　经过以上分页处理，得到：
        //   $pageTexts包含着所有页的数组
        // 标记目录项的正则表达式
        // 第一个括号返回目录级别，第二个返回h标签参数，每三个返回<hn>和</hn>之间的内容
        $pagenum = count($pageTexts);
        $tocnum = 0;
        if ($P['makefcontents'] || $P['system-toc']) {
            $contentslevel = 6;
            if ($P['contentslevel']) {
                if ($P['contentslevel'] >= 1 && $P['contentslevel'] <= 6) {
                    $contentslevel = trim($P['contentslevel']);
                }
            }
            if ($contentslevel == 1) {
                $LevelRegex = '#<h(1)([^>]*?)>(.*?)<\/h1>#i';
            } else {
                $LevelRegex = '#<h([1-' . $contentslevel . '])([^>]*?)>(.*?)<\/h[1-' . $contentslevel . ']>#i';
            }
            $contMathchs = array();
            for ($i = 0; $i < $pagenum; $i++) {
                $matches = array();
                $pagetext = $pageTexts[$i];
                preg_match_all($LevelRegex, $pagetext, $matches, PREG_SET_ORDER);
                $contMatches[] = $matches;
                $contTemp = preg_split($LevelRegex, $pagetext);
                $contl = count($matches);
                $pageTexts[$i] = $contTemp[0];
                for ($j = 0; $j < $contl; $j++) {
                    if ($matches[$j][0]) {
                        $pageTexts[$i] .= '<a name="hntoc_' . $tocnum++ . '"></a>' . $matches[$j][0] . $contTemp[$j + 1];
                    } else {
                        $pageTexts[$i] .= $contTemp[$j + 1];
                    }
                }
            }

            // 制作目录
            $TocHTML = plgContpageCreateTOC($row, $contMatches, $P);
        }

        // 取得当前页内容
        $row->text = '';
        if ($page > $pagenum)
            $page = $pagenum;
        if ($P['firstpagecontents']) {
            if ($page == 0) {
                $maintext = $TocHTML;
            } else {
                $maintext = $pageTexts[$page - 1];
            }
        } else {
            if ($P['makefcontents']) {
                $ftext = $TocHTML;
            } else {
                $ftext = '';
            }
            if ($page == 0) {
                $maintext = $ftext . $pageTexts[$page];
            } else {
                if ($pagenum == 1) {
                    $maintext = $ftext . $pageTexts[$page];
                } else {
                    $maintext = $pageTexts[$page];
                }
            }
        }

        // 替换目录标签
        if ($P['hrtagtoc']) {
            $HrPageRegex = '#<hr([^>]*?)class=(\"|\')system-toc(\"|\')([^>]*?)\/*>#iU';
            $maintext = preg_replace($HrPageRegex, $TocHTML, $maintext);
        }

        // 处理脚注
        // 首先检索本页以前的所有页中的脚注数目
        $footnum = 0;
        if ($P['firstpagecontents'] && $page == 0) {
            // 首页是目录页，而且目前访问的是首页，则不作任何脚注处理
        } else {
            $OpPageRegex = '#<footnote([^>]*?)\/*>#i';
            $curpage = $P['firstpagecontents'] ? $page - 1 : $page;
            $matches = array();
            if ($pagenum > 1 && $curpage > 0) {
                // 如果页数大于1,则先统计本页之前的脚注数目
                for ($i = 0; $i < $curpage; $i++) {
                    $footnum += preg_match_all($OpPageRegex, $pageTexts[$i], $matches);
                }
            }
            $matches = array();
            $n = preg_match_all($OpPageRegex, $maintext, $matches, PREG_SET_ORDER);
            $footnote = '';
            if ($n) {
                $footTemp = preg_split($OpPageRegex, $maintext);
                $footl = count($matches);
                $footText = $footTemp[0];
                for ($j = 0; $j < $footl; $j++) {
                    if ($matches[$j][0]) {
                        $footText .= '<a name="footnotetoc_' . ++$footnum . '"></a>'
                                . '<sup><a href="' . $P['thisurl'] . '#footnote_' . $footnum . '">' .
                                $footnum . '</a></sup>' . $footTemp[$j + 1];
                    } else {
                        $footText .= $footTemp[$j + 1];
                    }
                    $options = JUtility::parseAttributes($matches[$j][0]);
                    if (array_key_exists('text', $options)) {
                        $footnote .= '<a href="' . $P['thisurl'] . '#footnotetoc_' . $footnum . '">^</a>' . $footnum;
                        $footnote .= '<a name="footnote_' . $footnum . '"></a>.' . $options['text'] . '<br />';
                    }
                }
                $maintext = $footText;
                if ($footnote) {
                    $maintext .= '<hr /><font size=-1>' . $footnote . '</font>';
                }
            }
        }

        // 加入页面上下部的导航条
        if ($pagenum > 1 || $P['firstpagecontents']) {
            $pagetext = plgContpageCreateNavigation($page, $pagenum, $P);
            $row->text = '<div class="pagenavbar">' . $pagetext . '</div><br />';
            $row->text .= $maintext;
            $row->text .= '<br />';
            $row->text .= '<div class="pagenavbar">' . $pagetext . '</div><br />';
        } else {
            $row->text = $maintext;
            $row->text .= '<br />';
        }

        return true;
    }

}